package br.com.loja.mvp.presenter;

import br.com.loja.mvp.model.BusinessPresenter;
import javax.persistence.Id;
import javax.swing.JOptionPane;
import br.com.loja.model.service.Service;
import br.com.loja.model.service.exception.ServiceException;
import br.com.loja.model.service.factory.ServiceFactory;
import br.com.loja.util.i18n.Language;
import br.com.loja.util.reflection.JBean;
import br.com.loja.util.reflection.ReflectionUtil;
import java.lang.reflect.ParameterizedType;
import java.util.List;

/**
 * @brief Classe AbstractEntityPresenter
 * @author David Luiz
 * @date 24/11/2014
 */
public class DefaultEditorPresenter<T> implements Presenter<T> {

    private T model;
    private BusinessPresenter<T> view;
    private final Class<T> classModel;
    private final Service<T> service;
    private final ServiceFactory factory;
    private final Language language;

    public DefaultEditorPresenter(Class<T> classModel) throws ServiceException {
        this.classModel = classModel;
        this.factory = ServiceFactory.getServiceFactory();
        this.service = factory.getService(classModel);
        this.language = Language.getInstance();
    }

    public DefaultEditorPresenter(List<T> database) throws ServiceException {

        ParameterizedType listType = (ParameterizedType) database.getClass().getGenericSuperclass();

        this.classModel = (Class<T>) listType.getActualTypeArguments()[0];
        this.factory = ServiceFactory.getServiceFactory();
        this.service = factory.getService(classModel);
        this.language = Language.getInstance();
    }

    @Override
    public void setView(BusinessPresenter<T> view) {
        this.view = view;
    }

    @Override
    public void newEntity() {
        this.model = null;
        view.setModel(getModel());
        view.newEntity();
    }

    @Override
    public void editEntity() {
        view.editEntity();
    }

    @Override
    public void removeEntity() {

        setModel(view.getModel());

        try {

            int option = JOptionPane.showConfirmDialog(null, "Deseja realmente remover este item?",
                    language.getString("remove"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);

            if (isOptionYes(option)) {
                service.remove((T) model);
                view.removeEntity();
                JOptionPane.showMessageDialog(null, "Operação concluida com sucesso!", language.getString("remove"), JOptionPane.INFORMATION_MESSAGE);
            } else {
                cancel();
            }
        } catch (Exception e) {
            //TODO ...Implementar log e tratamento...
            System.err.println(e.getMessage());
            JOptionPane.showMessageDialog(null, "Operacão não concluida!", language.getString("remove"), JOptionPane.ERROR_MESSAGE);
            e.printStackTrace();
        }
    }

    private boolean isOptionYes(int option) {
        return (option) == JOptionPane.YES_OPTION;
    }

    @Override
    public void saveEntity() {

        try {
            executeSave();
            JOptionPane.showMessageDialog(null, "Operação concluida com sucesso!", language.getString("save"), JOptionPane.INFORMATION_MESSAGE);
            view.saveEntity();
        } catch (Exception e) {
            //TODO ...Implementar log e tratamento...
            System.err.println(e.getMessage());
            JOptionPane.showMessageDialog(null, "Operacão não concluida!", language.getString("save"), JOptionPane.ERROR_MESSAGE);
            cancel();
            e.printStackTrace();
        }
    }

    private void executeSave() {

        String fieldIDName = ReflectionUtil.getFieldByAnnotation(classModel, Id.class).get(0).getName();
        Object oldID, newID;
        JBean bean = new JBean(model, fieldIDName);
        oldID = bean.getValue();
        setModel(view.getModel());
        newID = bean.getValue();

        if (isNewPrimaryKey(oldID)) {
            if (isSamePrimaryKey(oldID, newID)) {
                service.update((T) model);
            }
        } else {
            service.save((T) model);
        }
    }

    private boolean isNewPrimaryKey(Object oldID) {
        return oldID != null;
    }

    private boolean isSamePrimaryKey(Object oldID, Object newID) {
        return oldID.equals(newID);
    }

    @Override
    public void cancel() {
        view.cancel();
    }

    @Override
    public void setModel(T model) {
        this.model = model;
    }

    @Override
    public T getModel() {
        if (this.model == null) {
            this.model = (T) ReflectionUtil.getBeanInstance(classModel.getName());
        }
        return this.model;

    }

    @Override
    public Class<T> getClassModel() {
        return classModel;
    }

}
